import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RunGame {
	static int tickLength = 500;
	private static Map m;
	private static Player[] player;
	private static DoublyLinkedList<String> command;

	public static void main(String[] args) {

		String[] maze = { "******************************",
				"******.....................***",
				"****......&&&................*",
				"***...*.....................**",
				"**....*****&&........*....****",
				"******...................*****",
				"*...........*.............****",
				"*..........................***",
				"*.......*.......&......**....*",
				"*......***.....&.............*",
				"**.....&&.....&..............*",
				"***.....&....&&............***",
				"****....&&..&&............****",
				"*****...&&..&............*****",
				"******...&&&..............****",
				"****....&&.................***",
				"**......&..........*.......***",
				"*.......&&.........**.....****",
				"*........&&.......***....*****",
				"*****.....&&...............***",
				"**********&&...............***",
				"********&&&..................*",
				"**...&&&&.........*..........*",
				"*...........................**",
				"*......*.....................*",
				"*......*..............**.....*",
				"*.............*.............**",
				"**.............*...........***",
				"****...........**...........**",
				"******************************" };
		System.out.println("Loading...");
		m = new Map(maze);

		Item[] items = new Item[5];
		items[0] = new Item(13, 13, 40, items, 0);
		items[1] = new Item(14, 13, 40, items, 1);
		items[2] = new Item(15, 13, 40, items, 2);
		items[3] = new Item(16, 13, 41, items, 3);
		items[4] = new Item(17, 13, 41, items, 4);
		
		Resource[] resources = new Resource[3];
		resources[0] = new Gold(10, 12);
		resources[1] = new Gold(7, 7);
		resources[2] = new Gold(14, 8);
		
		for (int i = 0; i < resources.length; i++) {
			Tile tile = m.getTile(resources[i].getX(), resources[i].getY());
			tile.addResource(resources[i]);
		}
		AreaEffect[] ae=new AreaEffect[3];
		ae[0]=new AreaEffect(25,25,60);
		ae[1]=new AreaEffect(17,14,61);
		ae[2]=new AreaEffect(16,16,63);
		for(int i=0;i<3;i++)
		{
		Tile t = m.getTile(ae[i].getX(), ae[i].getY());
		t.addAreaEffect(ae[i]);
		}
		
		for (int i = 0; i < items.length; i++) {
			Tile tile = m.getTile(items[i].getX(), items[i].getY());
			tile.addItem(items[i]);
		}

		Decal[] decals = new Decal[6];
		decals[0] = new Decal(25, 25, 50);
		decals[1] = new Decal(16, 16, 50);

		player = new Player[1];
		command = new DoublyLinkedList<String>();
		player[0] = new Player(1, 6, 6,m);
		KeyDecoder KD = new KeyDecoder();

		KeyboardListener KL = new KeyboardListener();

		Clock clk = new Clock();
		long TimeStamp = clk.getTick();
		String key = "";

		player[0].makeExplorer(m.getTile(7, 1));
		player[0].makeExplorer(m.getTile(8, 1));
		player[0].makeColonist(m.getTile(5, 6));
		//player[0].makeColonist(m.getTile(3, 22));
		//player[0].makeColonist(m.getTile(27, 28));
		//player[0].makeBase(m.getTile(16, 16));
		//player[0].makeFarm(m.getTile(15, 16));
		player[0].makeArmy(m.getTile(15, 15));
		player[0].makeArmy(m.getTile(17, 17));
		
		Ticker tickCount= new Ticker();
		int count = 0;		
		
		Cursor cursor = new Cursor(0, 0, m.width() - 1, m.height() - 1,
				player[0].getTileables(), player[0].getArrayOfSizes());
		View view = new View(cursor, maze, decals, resources, items, KL, player, tickCount);



		while (true) {
			if ((count) % 100 == 0) {
				view.refresh(1);
			}
			if (count % tickLength == 0) {
				view.refresh(0);
				view.refresh(2);
				view.refresh(3);
			}
			key = "noKeyPressed";
			KD.decode(KL.getKeyEvent());
			command = KD.getCommandQueue();
			// if(!(GC.Command.isEmpty())){
			if (!(command.isEmpty())) {
				TimeStamp = clk.getTick();
				key = command.removeFirst();
			}
			if (key.equals("Alt + S")) {
				view.setFocus(1);

			}
			if (key.equals("FOCUS")) {
				if (cursor.getSelected().getType() == 30) {
					if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
							.equals("Move")) {
						if ((cursor.getdx() > -1) && (cursor.getdy() > -1)) {
							int[] cmd = { 0, cursor.getdx(), cursor.getdy() };
							cursor.getSelected().addCommand(cmd);
							cursor.setdxdy(-1, -1);
						} else {
							cursor.setdxdy(cursor.getSelected().getX(), cursor
									.getSelected().getY());
						}
					}
					
				}
			} else if (key.equals("SW")) {
				if (cursor.getSelected().getType() == 30) {
					if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
							.equals("Move")) {
						if ((cursor.getdx() > -1) && (cursor.getdy() > -1)) {
							if (destinationCheck(cursor.getdx() - 1, cursor
									.getdy() + 1)) {
								cursor.incdxdy(-1, 1);
							}
						}
					}
					else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Attack"))
					{
						int[] i = {1,-1,1};
						cursor.getSelected().addCommand(i);
					}
					else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Defend"))
					{
						int[] i = {2,-1,1};
						cursor.getSelected().addCommand(i);
					}
				}
			}

			else if (key.equals("S")) {
				if (cursor.getSelected().getType() == 30) {
					if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
							.equals("Move")) {
						if ((cursor.getdx() > -1) && (cursor.getdy() > -1)) {
							if (destinationCheck(cursor.getdx() - 0, cursor
									.getdy() + 1)) {
								cursor.incdxdy(0, 1);
							}
						}
					}
					else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Attack"))
					{
						int[] i = {1,0,1};
						cursor.getSelected().addCommand(i);
					}
					else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Defend"))
					{
						int[] i = {2,0,1};
						cursor.getSelected().addCommand(i);
					}
				}
			}

			else if (key.equals("SE")) {
				if (cursor.getSelected().getType() == 30) {
					if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
							.equals("Move")) {
						if ((cursor.getdx() > -1) && (cursor.getdy() > -1)) {
							if (destinationCheck(cursor.getdx() + 1, cursor
									.getdy() + 1)) {
								cursor.incdxdy(1, 1);
							}
						}
					}
					else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Attack"))
					{
						int[] i = {1,1,1};
						cursor.getSelected().addCommand(i);
					}
					else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Defend"))
					{
						int[] i = {2,1,1};
						cursor.getSelected().addCommand(i);
					}
				}
			}

			else if (key.equals("W")) {
				if (cursor.getSelected().getType() == 30) {
					if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
							.equals("Move")) {
						if ((cursor.getdx() > -1) && (cursor.getdy() > -1)) {
							if (destinationCheck(cursor.getdx() - 1, cursor
									.getdy() + 0)) {
								cursor.incdxdy(-1, 0);
							}
						}
					}
					else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Attack"))
					{
						int[] i = {1,-1,0};
						cursor.getSelected().addCommand(i);
					}
					else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Defend"))
					{
						int[] i = {2,-1,0};
						cursor.getSelected().addCommand(i);
					}}
			}

			else if (key.equals("E")) {
				if (cursor.getSelected().getType() == 30) {
				if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
						.equals("Move")) {
					if ((cursor.getdx() > -1) && (cursor.getdy() > -1)) {
						if (destinationCheck(cursor.getdx() + 1,
								cursor.getdy() + 0)) {
							cursor.incdxdy(1, 0);
						}
					}
				}
				else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Attack"))
				{
					int[] i = {1,1,0};
					cursor.getSelected().addCommand(i);
				}
				else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Defend"))
				{
					int[] i = {2,1,0};
					cursor.getSelected().addCommand(i);
				}
				}
			}

			else if (key.equals("NW")) {
				if (cursor.getSelected().getType() == 30) {
				if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
						.equals("Move")) {
					if ((cursor.getdx() > -1) && (cursor.getdy() > -1)) {
						if (destinationCheck(cursor.getdx() - 1,
								cursor.getdy() - 1)) {
							cursor.incdxdy(-1, -1);
						}
					}
					
				}
				else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Attack"))
				{
					int[] i = {1,-1,-1};
					cursor.getSelected().addCommand(i);
				}
				else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Defend"))
				{
					int[] i = {2,-1,-1};
					cursor.getSelected().addCommand(i);
				}
				}
			}

			else if (key.equals("N")) {
				if (cursor.getSelected().getType() == 30) {
				if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
						.equals("Move")) {
					if ((cursor.getdx() > -1) && (cursor.getdy() > -1)) {
						if (destinationCheck(cursor.getdx() + 0,
								cursor.getdy() - 1)) {
							cursor.incdxdy(0, -1);
						}
					}
				}
				else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Attack"))
				{
					int[] i = {1,0,-1};
					cursor.getSelected().addCommand(i);
				}
				}
			}

			else if (key.equals("NE")) {
				if (cursor.getSelected().getType() == 30) {
				if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
						.equals("Move")) {
					if ((cursor.getdx() > -1) && (cursor.getdy() > -1)) {
						if (destinationCheck(cursor.getdx() + 1,
								cursor.getdy() - 1)) {
							cursor.incdxdy(1, -1);
						}
					}
				}
				else if(cursor.getSelected().gettxtCommands()[cursor.getOrder()].equals("Attack"))
				{
					int[] i = {1,1,-1};
					cursor.getSelected().addCommand(i);
				}
				}
			}
			if (key.equals("CTRL + DOWN")) {
				cursor.toggle(0, 1);
			} else if (key.equals("CTRL + UP")) {
				cursor.toggle(0, -1);
			} else if (key.equals("CTRL + LEFT")) {
				cursor.toggle(1, -1);
			} else if (key.equals("CTRL + RIGHT")) {
				cursor.toggle(1, 1);
			} else if (key.equals("LEFT")) {
				cursor.toggle(2, -1);
			} else if (key.equals("RIGHT")) {
				cursor.toggle(2, 1);
			} else if (key.equals("DOWN")) {
				cursor.toggle(3, 1);
			} else if (key.equals("UP")) {
				cursor.toggle(3, -1);
			} else if (key.equals("ENTER")) {
				if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
						.equals("Decommission")) {

					// System.out.println("from rungame "+cursor.getSelected().getID()+" "+cursor.getSelected().getStatus()[0]);
					if (cursor.getSelected().getType() == 10
							|| cursor.getSelected().getType() == 11)// base or
						// farm
						player[0].destroyStructure(cursor.getSelected()
								.getStatus()[0]);
					else
						player[0]
								.destroyUnit(cursor.getSelected().getStatus()[0]);
				} else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("Power down")) {
					cursor.getSelected().powerDown();
				} else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("Power up")) {
					cursor.getSelected().powerUp();
				} else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("Cancel orders")) {
					cursor.getSelected().delCommands();
				}

			else if (cursor.getSelected().gettxtCommands()[cursor
			                         						.getOrder()].equals("Wait")) {
				int[] cmd ={3};
			                         					cursor.getSelected().addCommand(cmd);
			                         				}
				
				else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("Disband")) {
					((Rally) cursor.getSelected()).disband();
				} else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("   Explorer")) {
					int[] i = { 1, 20 };
					cursor.getSelected().addCommand(i);

				} else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("   Colonist")) {
					int[] i = { 2, 30 };
					cursor.getSelected().addCommand(i);
				} else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("   Melee")) {
					int[] i = { 3, 40 };
					cursor.getSelected().addCommand(i);
				} else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("   Range")) {
					int[] i = { 4, 50 };
					cursor.getSelected().addCommand(i);
				} else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("   Base")) {

					int[] i = { 4, 20 };
					cursor.getSelected().addCommand(i);

				} else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("   Farm")) {

					int[] i = { 5, 10 };
					cursor.getSelected().addCommand(i);
				}else if (cursor.getSelected().gettxtCommands()[cursor
						.getOrder()].equals("Heal")) 
					{
					
					Unit u=m.getTile(cursor.getSelected().getX(),cursor.getSelected().getY()).getMinHPUnit();
					if (u!=null)
					{
						
					((Base)cursor.getSelected()).doHealUnit(u);
					}
					
				}
			}
			 else {
				Pattern pattern = Pattern.compile("\\d");
				Matcher matcher = pattern.matcher(key);
				while (matcher.find()) {
					int x = Integer.parseInt(matcher.group());
					if (x == 0) {
						x = 10;
					}
					x--;
					if (cursor.getSelected().gettxtCommands()[cursor.getOrder()]
							.equals("Go to rally")) {
						if (player[0].getArrayOfSizes()[2][0] > x) {
							int[] cmd = { 0, x };
							// ((Unit)cursor.getSelected()).delCommands();
							cursor.getSelected().addCommand(cmd);
							if (((Unit) cursor.getSelected()).getRally() != null) {
								((Unit) cursor.getSelected()).getRally()
										.remUnit((Unit) cursor.getSelected());
							}
							player[0].rally[x].addUnit((Unit) cursor
									.getSelected());
						}
					} else {
						cursor.goTo(x);
					}
				}
			}

			count++;
			if (count == tickLength + 1) {
				Tileable[][][] tileables = player[0].getTileables();
				int[][] size = player[0].getArrayOfSizes();
				for (int i = 0; i < tileables[0].length; i++) {
					for (int j = 0; j < size[0][i]; j++) {
						if(tileables[0][i][j]==null)
						{
							System.out.print("errror at i "+i+" j "+j+" size "+size[0][1]+" colonists "+player[0].colonistSize);
						}
						else
						{
					
						tileables[0][i][j].doMove(m);
						}
					}
				}

				for (int i = 0; i < player[0].rallySize; i++) {
					player[0].rally[i].doMove(m);

				}

				for (int i = 0; i < player[0].baseSize; i++) {
					player[0].base[i].doCreate(m);

				}
				for (int i = 0; i < player[0].farmSize; i++) {
					player[0].farm[i].doCreate(m);

				}
				
				
				
				count = 0;
				tickCount.incTick();
			}
			delay(1);
		}

		// player[0].colonist[0].move(m, 8,28);
		/*
		 * while(true) { for(int i = 0; i< player[0].getUnitSize(); i++) {
		 * System.out.println("Unit ID: "+player[0].unit[i].getID()+
		 * " Type: "+player[0].unit[i].getType()+
		 * " has Health: "+player[0].unit[i].getHealth()); }
		 * player[0].consumeFood(); if(player[0].getFood()==0) { for(int i = 0;
		 * i< player[0].getUnitSize(); i++) player[0].unit[i].weaken(1); }
		 * for(int i = 0; i< player[0].explorerSize; i++) {
		 * if(player[0].explorer[i].getHealth()==0)
		 * player[0].killExplorer(player[0].explorer[i].getID()); }
		 * System.out.println(player[0].toString()); System.out.println();
		 * delay(3000); }
		 */

	
	}

	private static boolean destinationCheck(int x, int y) {
		boolean b = true;
		Tile tempTile = m.getTile(x, y);
		char c = tempTile.getLabel();
		if (c == '*' || c == '&')
			b = false;
		return b;
	}

	private static void addCommand(String _Command) {
		command.addBack(_Command);
	}

	private static void delay(int t) {
		try {
			Thread.sleep(t);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

/*
 * 
 * 
 * String [] smallMaze = { "*****", "*..e*", "*.***", "*s..*", "*****" };
 * 
 * String[] smallmaze = { "****************", "*.*.*.**.......*",
 * "*...*.**.*.***.*", "*.***.**.*..**.*", "*.....**.****..*",
 * "*.***.**....*.**", "*.*.*.**.*.**.**", "***.*.**.*.**.**",
 * "*..*.....*.**.**", "*.*.**.***.*****", "*.*.**.***.*****",
 * "***.**.***...***", "*...**.*****.***", "*.******...*.***",
 * "*........*...***", "****************" };
 * 
 * Unit u = new Unit(101,'u'); Structure s = new Structure(201, 's'); Item i =
 * new Item(301,'i'); Resource r = new Resource(401,'r'); Army a = new Army(501,
 * 'a', 1); u.move(m);
 * 
 * delay(1000); m.getTile(1,3).setLabel('.'); m.getTile(1,2).setLabel('s');
 * u.move(m); System.out.println(m.toString()); delay(1000);
 * m.getTile(1,2).setLabel('.'); m.getTile(1,1).setLabel('s'); u.move(m);
 * System.out.println(m.toString()); delay(1000); m.getTile(1,1).setLabel('.');
 * m.getTile(2,1).setLabel('s'); u.move(m); System.out.println(m.toString()); /*
 * TileAssoc ta1 = new TileAssoc(m.getTile(14,1)); ta1.putTileable(u); TileAssoc
 * ta2 = new TileAssoc(m.getTile(14,3)); ta2.putTileable(s); TileAssoc ta3 = new
 * TileAssoc(m.getTile(10,3)); ta3.putTileable(i); TileAssoc ta4 = new
 * TileAssoc(m.getTile(8,1)); ta4.putTileable(r);
 */

// TileAssoc ta5 = new TileAssoc(m.getTile(14,1));
// ta1.putTileable(u);
// System.out.println(ta1.toString());

// System.out.print(m.toString());
// System.out.println();

// TESTING SAMPLE MOVE
/*
 * ta1.remTileable(101); ta1.setTile(m.getTile(14,2)); ta1.putTileable(u);
 * 
 * System.out.print(m.toString()); System.out.println();
 */

// ta1.remTileable(101);
// System.out.print(m.toString());

// TESTING Tile, Tileable, TileAssoc
/*
 * System.out.println("adding a new tileable");
 * 
 * Tileable t1 = new Tileable(200,'d','1'); Tileable t2 = new
 * Tileable(400,'d','2'); Tileable t3 = new Tileable(600,'d','3'); Unit u1 = new
 * Unit(100,'u'); TileAssoc ta = new TileAssoc(m.tiles[3][1]);
 * 
 * 
 * System.out.println(m.tiles[3][1].getLabel());
 * 
 * ta.putTileable(u1); ta.putTileable(t1); ta.putTileable(t2);
 * ta.putTileable(t3);
 * 
 * System.out.println(m.tiles[3][1].getLabel());
 * System.out.println(ta.toString()); System.out.println("removing a tileable");
 * ta.remTileable(600); System.out.println(ta.toString());
 * System.out.println(m.tiles[3][1].getLabel());
 * 
 * ta.remTileable(400); System.out.println(ta.toString());
 * System.out.println(m.tiles[3][1].getLabel());
 * 
 * ta.remTileable(200); System.out.println(ta.toString());
 * System.out.println(m.tiles[3][1].getLabel());
 * 
 * System.out.println(); System.out.print(m.toString());
 */
/*
 * Map m = new Map(); System.out.println(); System.out.print(m.toString()); Unit
 * u = new Unit(3,1); System.out.println(u.toString()); u =
 * m.tiles[3][1].putUnitToTile(u); System.out.println(u.toString());
 * m.changeTile(3,1,4,1,'u'); System.out.println(u.toString());
 * System.out.println("Start Game"); u.move(m); m.changeTile(0, 0, 'x');
 * System.out.println(); System.out.print(m.toString());
 */
